home *** CD-ROM | disk | FTP | other *** search
Text File | 1994-11-21 | 11.5 KB | 516 lines | [TEXT/MPCC] |
- /*
- ** CTCPDriver.cp
- **
- ** TurboTCP support library
- ** TCP driver interface class
- **
- ** Copyright © 1993-94, FrostByte Design / Eric Scouten
- **
- */
-
- #include "CTCPDriver.h"
-
- #include "CApplication.h"
- #include "CBartender.h"
- #include "CDLOGDirector.h"
- #include "CPtrArray.h"
- #include "CVoidPtrArrayIterator.h"
-
- #if (defined(GENERATINGPOWERPC) || defined(GENERATING68K))
- #include <MacTCP.h> // Universal Headers 2.0
- #else
- #include <GetMyIPAddr.h> // Univ Headers 1.0 or old headers
- #endif
-
- #include "CTCPApplication.h"
- #include "CTCPAsyncCall.h"
- #include "CTCPStream.h"
- #include "CTCPResolverCall.h"
-
-
- // resource definitions
-
- #define DLOG_TCPDelayedQuit 23010
-
-
- // TCL global variables
-
- extern CApplication* gApplication;
- extern CBartender* gBartender;
-
-
- // CTCPDriver static variables
-
- CTCPDriver* CTCPDriver::gTCPDriver = NULL;
-
-
- // declare special list classes used here
-
- #ifndef TCL_NO_TEMPLATES
- class CTCPStreamList : public CPtrArray<CTCPStream> {};
- class CTCPResolverCallList : public CPtrArray<CTCPResolverCall> {};
- #else
- CW_Decl_PtrArray(CTCPStream)
- CW_Decl_PtrArray(CTCPResolverCall)
- #endif
-
-
- //______________________________________________________________________
- //
- // All routines are private interfaces for the use of TurboTCP classes ONLY!
- // They are subject to change in future versions. Be forewarned!
- //
- //______________________________________________________________________
-
-
- // —— contructor/destructor ——
-
- /*______________________________________________________________________
- **
- ** constructor
- **
- ** Clear the TCP driver object. Check to see if MacTCP is open. Optionally, opens TCP
- ** resolver.
- **
- ** doOpenResolver (Boolean): TRUE to open TCP resolver as well
- **
- */
-
- CTCPDriver::CTCPDriver()
-
- {
-
- // clear variables
-
- hasMacTCP = FALSE;
- hasResolver = FALSE;
- myTCPRefNum = 0;
- myIPAddress = 0L;
- gTCPDriver = this;
- activeStreamList = NULL;
- activeResolverList = NULL;
-
-
- // if on PowerPC, get completion procedure (which is 68K code)
-
- CTCPAsyncCall::GetCompletionProc();
-
-
- // clear asynch processing queue
-
- asyncQueue.qFlags = 0;
- asyncQueue.qHead = NULL;
- asyncQueue.qTail = NULL;
-
-
- // create the active TCP/DNR call lists
-
- activeStreamList = new CTCPStreamList;
- activeResolverList = new CTCPResolverCallList;
-
- }
-
-
- /*______________________________________________________________________
- **
- ** Dispose
- **
- ** Dispose of this object and any lingering TCP async call objects or TCP stream objects.
- ** It is CRITICAL that any lingering TCP streams be closed, released, and disposed;
- ** otherwise MacTCP is *guaranteed* to crash the machine when the next app launches.
- ** If the resolver is open, wait until all resolver queries have been cancelled.
- **
- ** If at least one second elapses between the start of this routine and the end, flash a
- ** dialog box to indicate the reason for the delay.
- **
- ** The ‘Dispose’ method is retained in TCL 2.0 because the driver object may need to
- ** delay its destruction.
- **
- */
-
- void CTCPDriver::Dispose()
-
- {
- register long i;
- void* theStreamPtr;
- CTCPStream* theStream;
- unsigned long startTickCount;
- unsigned long theTime;
- CDLOGDirector* theDialog = NULL;
-
-
-
- // cancel outstanding DNR calls & close resolver
-
- if (hasResolver)
- CTCPResolverCall::CloseResolver();
-
-
- // kill any lingering streams
-
- if (activeStreamList) {
- CVoidPtrArrayIterator streams(activeStreamList, kStartAtBeginning);
-
- // CTCPStreamIterator streams(activeStreamList, kStartAtBeginning);
- // #ifndef TCL_NO_TEMPLATES
- // CPtrArrayIterator<CTCPStream> streams(activeStreamList, kStartAtBeginning);
- // #else
- // CPtrArrayIterator_CTCPStream streams(activeStreamList, kStartAtBeginning);
- // #endif
-
- while (streams.Next(theStreamPtr)) {
- theStream = (CTCPStream*&) theStreamPtr;
- theStream->PostponeDispose();
- }
- }
-
-
- // wait for TCP to be done with everything
-
- GetDateTime(&startTickCount);
- gBartender->DisableMenuBar(); // disable all menus
-
- while (!activeStreamList->IsEmpty()) {
-
-
- // do a private event loop & toss up a dialog if it takes more than 2 seconds
-
- GetDateTime(&theTime);
- if ((theDialog == NULL) && (theTime - startTickCount >= 2)) {
- theDialog = new CDLOGDirector(DLOG_TCPDelayedQuit, gApplication);
- theDialog->BeginDialog();
- }
-
-
- // wait for TCP completions & terminations
-
- gApplication->Process1Event();
-
- }
-
-
- // get rid of dialog box (if there was one)
-
- ForgetObject(theDialog);
-
-
- // dispose all the objects
-
- ForgetObject(activeStreamList);
- ForgetObject(activeResolverList);
- delete this;
-
- }
-
-
- // —— event handling ——
-
- /*______________________________________________________________________
- **
- ** ProcessOneNetEvent
- **
- ** Respond to all delayed TCP notifications, completions, disposals. This routine should be
- ** hooked into the application’s event loop or some very frequently called routine.
- **
- ** return (Boolean): TRUE if there are more asynchronous events in the queue
- **
- */
-
- Boolean CTCPDriver::ProcessOneNetEvent()
-
- {
- void* theAsyncObject;
- TurboTCPQElemPtr theAsyncEntry;
- CTCPAsyncCall* theAsyncCall;
- CTCPResolverCall* theResolverCall;
- CTCPStream* theStream;
-
-
- // if no events, quit now
-
- if (asyncQueue.qHead == NULL)
- return FALSE;
-
-
- // figure out what object caused the notification
-
- theAsyncEntry = (TurboTCPQElemPtr) asyncQueue.qHead;
- theAsyncObject = (CCollaborator*) theAsyncEntry->qSelfLink;
-
-
- // remove it from the queue (just in case the event processing fails)
-
- Dequeue((QElemPtr) theAsyncEntry, &asyncQueue);
-
-
- // process the event
-
- switch (theAsyncEntry->qType) {
- case asyncCall:
- theAsyncCall = (CTCPAsyncCall*) theAsyncObject;
- if (theAsyncCall)
- theAsyncCall ->ProcessCompletion();
- break;
- case resolverCall:
- theResolverCall = (CTCPResolverCall*) theAsyncObject;
- if (theResolverCall)
- theResolverCall->ProcessNotify();
- break;
- case notifyStream:
- theStream = (CTCPStream*) theAsyncObject;
- if (theStream)
- theStream->ProcessNotify();
- break;
- case disposeStream:
- theStream = (CTCPStream*) theAsyncObject;
- if (theStream)
- theStream->Dispose();
- break;
-
- } // switch
-
-
- // tell caller whether there’s another call
-
- return (asyncQueue.qHead != NULL);
-
- }
-
-
- // —— TCP verification routines ——
-
- /*______________________________________________________________________
- **
- ** GetIPAddr (public static method)
- **
- ** Returns the current local IP address, if available. Fails with “noTCPError” error if
- ** MacTCP is not installed.
- **
- ** return (ip_addr): current IP address
- **
- */
-
- ip_addr CTCPDriver::GetIPAddr()
-
- {
- if (!(gTCPDriver->hasMacTCP))
- FailOSErr(noTCPError);
- return gTCPDriver->myIPAddress;
- }
-
-
- /*______________________________________________________________________
- **
- ** CheckTCPDriver
- **
- ** Check to see if the MacTCP driver is present. Should be done before opening each new
- ** connection (built into CTCPStream). If TCP driver is present, updates the current IP address.
- **
- ** return (Boolean): TRUE if MacTCP driver is present
- **
- */
-
- Boolean CTCPDriver::CheckTCPDriver()
-
- {
- ParamBlockRec theParamBlock;
- unsigned char theName[6] = "\p.IPP"; // MacTCP driver name
-
-
- // if TCP not already confirmed, look for it
-
- if (!hasMacTCP) {
- theParamBlock.ioParam.ioNamePtr = (StringPtr) &theName;
- theParamBlock.ioParam.ioPermssn = fsCurPerm;
- if ((short) PBOpenSync(&theParamBlock) == 0) {
- myTCPRefNum = theParamBlock.ioParam.ioRefNum;
- hasMacTCP = TRUE;
- }
- }
-
-
- /*
- ** If TCP driver available, get the IP address. This is done *each* time a new stream
- ** is created because the address might have changed. (This could happen on a machine
- ** connected by modem & SLIP, if the user hangs up the modem and re-dials the
- ** SLIP server without quitting the program.)
- */
-
- FetchIPAddr();
- return hasMacTCP;
-
- }
-
-
- /*______________________________________________________________________
- **
- ** CheckResolver
- **
- ** Check to see if the MacTCP DNR code segment is available. If it isn’t, use the OpenResolver
- ** call to make it available.
- **
- ** return (Boolean): TRUE if TCP resovler is present
- **
- */
-
- Boolean CTCPDriver::CheckResolver()
-
- {
-
- TRY {
- CTCPResolverCall::OpenResolver();
- hasResolver = TRUE;
- }
- CATCH {
- hasResolver = FALSE;
- NO_PROPAGATE;
- }
- ENDTRY;
- return hasResolver;
-
- }
-
-
- /*______________________________________________________________________
- **
- ** GetTCPRefNum
- **
- ** Returns the Device Manager reference number for MacTCP, if available. Fails with
- ** “noTCPError” error if not available.
- **
- ** return (short): MacTCP driver refnum
- **
- */
-
- short CTCPDriver::GetTCPRefNum()
-
- {
- if (!(gTCPDriver->hasMacTCP))
- FailOSErr(noTCPError);
- return gTCPDriver->myTCPRefNum;
- }
-
-
- /*______________________________________________________________________
- **
- ** FetchIPAddr (protected method)
- **
- ** Retrieve the local host’s IP address. Does nothing if MacTCP is not available. Stores the
- ** new address in the local field myIPAddress, which can be retrieved with the
- ** GetIPAddr() method.
- **
- */
-
- void CTCPDriver::FetchIPAddr()
-
- {
- struct GetAddrParamBlock theIPParamBlock;
-
- myIPAddress = 0L;
-
- if (hasMacTCP) {
- theIPParamBlock.csCode = ipctlGetAddr;
- theIPParamBlock.ioCRefNum = myTCPRefNum;
- PBControlSync((ParmBlkPtr) &theIPParamBlock);
- if (theIPParamBlock.ioResult == noErr)
- myIPAddress = theIPParamBlock.ourAddress;
- }
- }
-
-
- // —— tracking active streams/resolvers ——
-
- /*______________________________________________________________________
- **
- ** RegisterActiveStream
- **
- ** Add a DNR resolver call to the list of active TCP streams. The driver object uses this
- ** information to ensure that all resolver calls are closed and terminated before the
- ** application quits.
- **
- ** theStream (CTCPStream*): the stream to register
- **
- */
-
- void CTCPDriver::RegisterActiveStream(CTCPStream* theStream)
-
- {
- activeStreamList->Append(theStream);
- }
-
-
- /*______________________________________________________________________
- **
- ** RegisterActiveResolver
- **
- ** Add a DNR resolver call to the list of active TCP streams. The driver object uses this
- ** information to ensure that all resolver calls are closed and terminated before the
- ** application quits.
- **
- ** theResolver (CTCPResolverCall*): the resolver call to register
- **
- */
-
- void CTCPDriver::RegisterActiveResolver(CTCPResolverCall* theResolver)
-
- {
- if (CheckResolverLimit()) // disallow 9th DNR call
- FailOSErr(resolverBusy);
- activeResolverList->Append(theResolver);
- }
-
-
- /*______________________________________________________________________
- **
- ** RemoveActiveStream
- **
- ** Remove a TCP stream from the list of active TCP streams. This message indicates that
- ** MacTCP is no longer dependent on the memory structure for the stream.
- **
- ** theStream (CTCPStream*): the stream to remove
- **
- */
-
- void CTCPDriver::RemoveActiveStream(CTCPStream* theStream)
-
- {
- if (activeStreamList) // just in case this is called during shutdown
- activeStreamList->Remove(theStream);
- }
-
-
- /*______________________________________________________________________
- **
- ** RemoveActiveResolver
- **
- ** Remove a DNR resolver call from the list of active calls. This message indicates that
- ** the MacTCP DNR is no longer dependent on the memory structure for the call.
- **
- ** theResolver (CTCPResolverCall*): the resolver call to remove
- **
- */
-
- void CTCPDriver::RemoveActiveResolver(CTCPResolverCall* theResolver)
-
- {
- if (activeResolverList) // just in case this is called during shutdown
- activeResolverList->Remove(theResolver);
- }
-
-
- /*______________________________________________________________________
- **
- ** CheckResolverLimit
- **
- ** Ensure that the DNR’s limit of 8 calls is not violated.
- **
- ** return (Boolean): TRUE if too many calls have been issued
- **
- */
-
- Boolean CTCPDriver::CheckResolverLimit()
-
- {
- return (activeResolverList->numItems) >= maxResolverCalls;
- }
-